﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Data;
using TouchControls.MenuFlows;
using System.Windows.Media.Animation;

namespace TouchControls
{
    internal class TouchMenuPanel : Panel
    {
        internal TouchMenuItem CurrentItem { get; private set; }
        internal TouchMenuItem CurrentItemParent { get; private set; }

        internal AdornmentGrid Adornment { get; private set; }

        internal TouchMenuContainer ItemsContainer { get; private set; }

        internal ITouchMenuFlow _flow;

        internal int Depth { get; private set; }

        private double _maxSize;

        internal int Space
        {
            get
            {
                return 6;
            }
        }

        internal int Distance
        {
            get
            {
                return 10;
            }
        }

        internal double LinesCoeff
        {
            get
            {
                return 0.3;
            }
        }

        internal double LinesThickness
        {
            get
            {
                return 3.0;
            }
        }



        public double Offset
        {
            get { return (double)GetValue(OffsetProperty); }
            set
            {
                SetValue(OffsetProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for Offset.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OffsetProperty =
            DependencyProperty.Register("Offset", typeof(double), typeof(TouchMenuPanel), new PropertyMetadata(1.0, new PropertyChangedCallback(OffsetChanged)));

        static void OffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as TouchMenuPanel).MoveItems();
        }

        public override void EndInit()
        {
            base.EndInit();
            CurrentItem = this.FindParent<TouchMenuItem>();
            CurrentItem.MenuOpening += new EventHandler(CurrentItem_MenuOpening);
            CurrentItemParent = CurrentItem.FindParent<TouchMenuItem>();
        }

        void CurrentItem_MenuOpening(object sender, EventArgs e)
        {
            this.AnimateMenus();
        }

        protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
        {
            Adornment = AdornmentGrid.For(this);
            ItemsContainer = this.FindParent<TouchMenuContainer>();
            Depth = ItemsContainer.GetDepth();
            this.CurrentItem.LineCanvas.Children.Clear();

            _flow = AbstractFlow.Get(this);

            if (_flow != null)
            {
                return _flow.Measure(availableSize);
            }
            return new Size(Adornment.RenderSize.Width, Adornment.RenderSize.Height);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (InternalChildren.Count == 0 || CurrentItem.ButtonRect == Rect.Empty) return base.ArrangeOverride(finalSize);

            if (_flow != null)
            {
                var item = InternalChildren[0] as TouchMenuItem;

                var res = _flow.Arrange(finalSize);
                AnimateMenus();

                CurrentItem.MenuContainer.InvalidateArrange();
                return base.ArrangeOverride(finalSize);
            }

            return base.ArrangeOverride(finalSize);
        }

        private void MoveItems()
        {
            foreach (var touchMenuItem in this._flow.Items)
            {
                if (touchMenuItem.ButtonRect == Rect.Empty)
                {
                    this.InvalidateArrange();
                    break;
                }

                if (this.Offset == 1.0)
                {
                    touchMenuItem.ApplyButtonPosition(touchMenuItem.ButtonRect);
                }

                var x = this.CurrentItem.ButtonRect.X + ((touchMenuItem.ButtonRect.X - this.CurrentItem.ButtonRect.X) * this.Offset);
                var y = this.CurrentItem.ButtonRect.Y + ((touchMenuItem.ButtonRect.Y - this.CurrentItem.ButtonRect.Y) * this.Offset);
                var rect = new Rect(x, y, touchMenuItem.ButtonRect.Width, touchMenuItem.ButtonRect.Height);
                touchMenuItem.ApplyButtonPosition(rect);
            }
        }

        private Storyboard _menuAnim;

        private void AnimateMenus()
        {
            if (_menuAnim != null)
            {
                _menuAnim.Stop();
            }
            foreach (var touchMenuItem in _flow.Items)
            {
                touchMenuItem.Animating = true;
            }
            _menuAnim = new Storyboard();
            var easing = new ElasticEase();
            easing.EasingMode = EasingMode.EaseOut;
            _menuAnim.Duration = new Duration(TimeSpan.FromMilliseconds(250));
            DoubleAnimation animOffset = new DoubleAnimation();
            animOffset.EasingFunction = easing;
            //animOffset.Duration = new Duration(TimeSpan.FromMilliseconds(500));

            animOffset.From = 0;
            animOffset.To = 1.0;
            Storyboard.SetTarget(animOffset, this);
            Storyboard.SetTargetProperty(animOffset, new PropertyPath("Offset"));
            _menuAnim.Children.Add(animOffset);
            //animOffset.Changed += new EventHandler(animOffset_Changed);
            _menuAnim.Completed += new EventHandler(menuAnim_Completed);
            _menuAnim.Begin();
            CurrentItem.LineCanvas.Visibility = Visibility.Hidden;            

            //menuAnim.Changed += new EventHandler(menuAnim_Changed);
        }

        void animOffset_Changed(object sender, EventArgs e)
        {
            this.UpdateLayout();
        }

        void menuAnim_Completed(object sender, EventArgs e)
        {
            CurrentItem.LineCanvas.Visibility = Visibility.Visible;
            foreach (var touchMenuItem in Children.Cast<UIElement>().Where(elt => elt is TouchMenuItem).Cast<TouchMenuItem>())
            {
                touchMenuItem.Animating = false;
            }
            if (_menuAnim != null)
            {
                _menuAnim.Stop();
                _menuAnim.Children.Clear();
                _menuAnim.Completed -= new EventHandler(menuAnim_Completed);
                _menuAnim = null;
            }
        }

        void menuAnim_Changed(object sender, EventArgs e)
        {
            this.UpdateLayout();
        }
    }
}
